#include <fuse.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>

#include <syslog.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
#include <time.h>

#include "LinuxFuse.h"
#include "logog.hpp"

#define SERVER_PORT 5000

LinuxFuse* fuse;

static int _getattr(const char *path, struct stat *stbuf) {
    INFO("getattr: %s", path);
    return fuse->getFileAttribute(path, stbuf);
}

static int _readdir(const char *path, void *buf, fuse_fill_dir_t filler,
        off_t offset, struct fuse_file_info *fi) {
    INFO("readdir: %s", path);
    std::vector<std::string> files = fuse->getFilesInDir(path);

    if (files.size() == 0) {
        syslog(LOG_NOTICE, "in dir %s no files", path);
    }

    for (int i = 0; i < files.size(); i++) {
        filler(buf, files.at(i).c_str(), NULL, 0);
        syslog(LOG_NOTICE, "in dir %s files: %s", path, files.at(i).c_str());
    }

    return 0;
}

static int _open(const char *path, struct fuse_file_info *fi) {
    INFO("open: %s", path);
    return fuse->openFile(path);
    /*if(strcmp(path, hello_path) == 0 )
    {
            if((fi->flags & 3) != O_RDONLY)
                    return -EACCES;
            return 0;
    }
    else if(strcmp(path, hello_path) != 0 )
    {
            if((fi->flags & 3) != O_RDONLY)
                    return -EACCES;
            return 0;
    }
    else
    {
            return -ENOENT;
    }
        
    return -ENOENT;
     */
}
//int(* fuse_operations::release)(const char *, struct fuse_file_info *)

static int _read(const char *path, char *buf, size_t size, off_t offset,
        struct fuse_file_info *fi) {
    INFO("read file: %s size %d offset %d", path, size, offset);
    return fuse->read(path, buf, size, offset);
}

void* _init() {
    LOGOG_INITIALIZE();
    fuse = new LinuxFuse("192.168.1.101", "5000");
    INFO ("Start serwera %d", getuid ());
    //TCPServer* server = new TCPServer(SERVER_PORT);

    return (void*) 0; //server;
}

void _destroy(void * ptr) {
    INFO("destroy");
    delete fuse;
}

int _rename(const char * oldFile, const char * newFile) {
    INFO("rename file old name: %s new name %s", oldFile, newFile);
    return fuse->rename(oldFile, newFile);
}

int _rmdir(const char * dir) {
    return -ENOENT;
}

int _mkdir(const char * dir, mode_t mode) {
    return -ENOENT;
}

int _unlink(const char * file) {
    return -ENOENT;
}

int _write(const char *, const char *, size_t, off_t, struct fuse_file_info *) {
    return -ENOENT;
}

int _create(const char *, mode_t, struct fuse_file_info *) {
    return -ENOENT;
}

int _release(const char *, struct fuse_file_info *) {
    return -ENOENT;
}

static struct hello_operations : fuse_operations {

    hello_operations() {
        getattr = _getattr;
        //int(*         readlink )(const char *, char *, size_t)
        //int(* 	mknod )(const char *, mode_t, dev_t)
        mkdir = _mkdir;
        unlink = _unlink;
        rmdir = _rmdir;
        //int(* 	symlink )(const char *, const char *)
        rename = _rename;
        //int(* 	link )(const char *, const char *)
        //int(* 	chmod )(const char *, mode_t)
        //int(* 	chown )(const char *, uid_t, gid_t)
        //int(* 	truncate )(const char *, off_t)
        //int(* 	utime )(const char *, struct utimbuf *)
        //int(* 	open )(const char *, struct fuse_file_info *)
        read = _read;
        write = _write;
        //int(* 	statfs )(const char *, struct statvfs *)
        //int(* 	flush )(const char *, struct fuse_file_info *)
        release = _relase;
        //int(* 	fsync )(const char *, int, struct fuse_file_info *)
        //int(* 	setxattr )(const char *, const char *, const char *, size_t, int)
        //int(* 	getxattr )(const char *, const char *, char *, size_t)
        //int(* 	listxattr )(const char *, char *, size_t)
        //int(* 	removexattr )(const char *, const char *)
        //int(* 	opendir )(const char *, struct fuse_file_info *)
        readdir = _readdir;
        //int(* 	releasedir )(const char *, struct fuse_file_info *)
        //int(* 	fsyncdir )(const char *, int, struct fuse_file_info *)
        init = _init;
        void(* destroy)(void *)
                //int(* 	access )(const char *, int)
                create = _create;
        //int(* 	ftruncate )(const char *, off_t, struct fuse_file_info *)
        //int(* 	fgetattr )(const char *, struct stat *, struct fuse_file_info *)
        //int(* 	lock )(const char *, struct fuse_file_info *, int cmd, struct flock *)
        //int(* 	utimens )(const char *, const struct timespec tv[2])
        //int(* 	bmap )(const char *, size_t blocksize, uint64_t *idx)
        //int(* 	ioctl )(const char *, int cmd, void *arg, struct fuse_file_info *, unsigned int flags, void *data)
        //int(* 	poll )(const char *, struct fuse_file_info *, struct fuse_pollhandle *ph, unsigned *reventsp)
    }
} hello_oper_init;

int main(int argc, char *argv[]) {
    return fuse_main(argc, argv, &hello_oper_init);
}
